package ui.client;

import java.util.ArrayList;
import java.util.HashMap;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.RootPanel;
import com.gwtext.client.core.EventObject;
import com.gwtext.client.data.Node;
import com.gwtext.client.dd.DD;
import com.gwtext.client.widgets.Button;
import com.gwtext.client.widgets.MessageBox;
import com.gwtext.client.widgets.Panel;
import com.gwtext.client.widgets.event.ButtonListenerAdapter;
import com.gwtext.client.widgets.form.FormPanel;
import com.gwtext.client.widgets.form.TextField;
import com.gwtext.client.widgets.layout.ColumnLayout;
import com.gwtext.client.widgets.layout.ColumnLayoutData;
import com.gwtext.client.widgets.tree.TreeNode;
import com.gwtext.client.widgets.tree.TreePanel;
import com.gwtext.client.widgets.tree.event.TreeNodeListenerAdapter;

public class Client implements EntryPoint
{
	private FormPanel loginpanel=new FormPanel();//loginpanel
	private TextField nametext=new TextField("name","name",130);
	private TextField pwdtext=new TextField("password","pwd",130);
	private Panel panel1=new Panel();//the login panel
	private Button loginbutton;//the login button
	
	private TreePanel mainpanel=new TreePanel();//the main friend list
	
	private ChatServiceAsync instance=ChatService.Util.getInstance();
	private AsyncCallback logincallback;
	private AsyncCallback sendcallback;
	private AsyncCallback getgroupcallback;
	private AsyncCallback receivecallback;
	private AsyncCallback presencecallback;//all the callback
	
	private ArrayList<Group>groups;
	private MyTreeNodeListener nodelistener=new MyTreeNodeListener();
	private HashMap<GroupEntry,ChatWindow>map=new HashMap<GroupEntry,ChatWindow>();
	//private HashMap<String,Status>statusmap=new HashMap<String,Status>();//store all the status info
	public String username;//store the login name
	
	public void onModuleLoad()
	{				
		loginpanel.setTitle("login");
		loginpanel.setWidth(220);
		loginpanel.setHeight(150);
		loginpanel.setShadow(true);
		loginpanel.setFrame(true);
		loginpanel.setBorder(true);
		loginpanel.setLabelWidth(70);
		DD loginpanelproxy=new DD(loginpanel);//the login panel			
		
		loginbutton = new Button("login", new ButtonListenerAdapter() {  
			public void onClick(Button button, EventObject e) 
			{  
				String name=nametext.getText();
				String pwd=pwdtext.getText();
				if(name.equals("")||pwd.equals(""))//if input is null
				{
					MessageBox.alert("pleae input the username and password");
				}
				else
				{
					instance.login("XMPP", name, pwd, "gmail.com","talk.google.com", 5222, logincallback);
					Client.this.username=name;
				}
			}  
		});
		
		loginpanel.add(nametext);
		loginpanel.add(pwdtext);
		pwdtext.setPassword(true);
		nametext.setValue("yaimdakiler");
		pwdtext.setValue("86264284");
		panel1.setLayout(new ColumnLayout());
		panel1.add(new Panel(),new ColumnLayoutData(.4));
		panel1.add(loginbutton,new ColumnLayoutData(.2));
		loginpanel.add(panel1);	
		
		mainpanel.setTitle("Main");		
		mainpanel.setWidth(200);
		mainpanel.setHeight(450);	
		mainpanel.setShadow(true);
		mainpanel.setFrame(true);
		mainpanel.setBorder(true);		
		DD dd1=new DD(mainpanel);		
		/************************************************
		 * set the login panel
		 ************************************************/		
		
		
		logincallback = new AsyncCallback() 
		{
            public void onSuccess(Object result) {
              // do some UI stuff to show success
            	//MessageBox.alert("login success");
            	String reply=(String)result;
            	System.out.println("login reply:"+reply);
            	instance.getGroups(getgroupcallback);//try to get group information               	
            }

            public void onFailure(Throwable caught) {
            	System.out.println("login failed...");
            }
        };             
        
        sendcallback=new AsyncCallback()
        {        
        	public void onSuccess(Object result)
        	{
        		String reply=(String)result;
        		System.out.println("send reply:"+reply);
        	}
        	
        	public void onFailure(Throwable caught)
        	{
        		System.out.println("send failure");
        	}
        };
        
        getgroupcallback=new AsyncCallback()
        {
        	public void onSuccess(Object result)
        	{
        		ArrayList<Group>list=(ArrayList<Group>)result;
        		Client.this.groups=list;//store the Group Arraylist
        		displayGroups();
        		instance.receive(receivecallback);
        		instance.presenceChange(presencecallback);
        	}
        	
        	public void onFailure(Throwable caught)
        	{
        		System.out.println("get groups failure...");
        	}
        };
        
        receivecallback=new AsyncCallback()
        {
        	public void onSuccess(Object result)
        	{             		  
        		ArrayList<InstantMessage>messages=(ArrayList<InstantMessage>)result;
        		dealMessages(messages);  
        		instance.receive(receivecallback);//go on receiving   
        	}
        	
        	public void onFailure(Throwable caught)
        	{
        		System.out.println("receive failure...");
        	}
        };
        
        presencecallback=new AsyncCallback()
        {
        	public void onSuccess(Object result)
        	{        		
        		ArrayList<UserPresence>list=(ArrayList<UserPresence>)result;
        		updatePresence(list);
        		instance.presenceChange(presencecallback);
        	}
        	public void onFailure(Throwable caught)
        	{
        		System.out.println("presence failure...");
        	}        	
        };
        /**************************************************
         * set the AsyncCallbacks
         **************************************************/
        
		RootPanel.get().add(loginpanel);		
	}	
	
	/**
	 * this method will display the group and friends info
	 */
	private synchronized void displayGroups()
	{
		//int x=mainpanel.getAbsoluteLeft();
		//int y=mainpanel.getAbsoluteTop();
		mainpanel.setVisible(false);	
		mainpanel=new TreePanel();
		mainpanel.setTitle("Main");		
		mainpanel.setWidth(200);
		mainpanel.setHeight(450);	
		//mainpanel.setPagePosition(x, y);
		mainpanel.setShadow(true);
		mainpanel.setFrame(true);
		mainpanel.setBorder(true);		
		DD dd1=new DD(mainpanel);
		
		System.out.println("display");
		loginpanel.setVisible(false);
		TreeNode root=new TreeNode("friends");
		for(int i=0;i<groups.size();i++)
		{
			Group group=groups.get(i);
			group.update();
			String name=group.getName();//get group name
			ArrayList<GroupEntry>entries=group.getGroupEntries();
			TreeNode groupnode=new TreeNode(name);
			root.appendChild(groupnode);
			for(int j=0;j<entries.size();j++)
			{
				GroupEntry entry=entries.get(j);			
				String alias=entry.getAlias();
				String id=entry.getID().toLowerCase();			
				MyTreeNode leaf=new MyTreeNode(alias,entry);				
				//System.out.println(id);
				System.out.println(id+":"+entry.getPresence().getStatus());
				leaf.addListener(nodelistener);
				if(entry.getPresence().getStatus()==Status.ONLINE)
				{			
					leaf.setIcon("001.png");
				}
				else
				{			
					leaf.setIcon("002.png");
				}						
				groupnode.appendChild(leaf);
			}
		}		
		mainpanel.setRootNode(root);
		mainpanel.doLayout();
		mainpanel.expandAll();
		mainpanel.setVisible(true);
		RootPanel.get().add(mainpanel);
	}
	
	/**
	 * this method will update the TreePanel according to the
	 * UserPresence
	 * @param list
	 */
	private void updatePresence(ArrayList<UserPresence>list)
	{				
		for(int i=0;i<list.size();i++)
		{
			UserPresence presence=list.get(i);
			String id=this.getShortId(presence.getUserID()).toLowerCase();//get id
			Status status=presence.getStatus();
			GroupEntry entry=this.getEntry(id);
			entry.setPresence(presence);
		}		
		this.displayGroups();
	}
	
	/**
	 * send to the dest
	 * @param message
	 * @param entry
	 */
	public void send(String message,GroupEntry entry)
	{
		System.out.println("send to dest");
		InstantMessage im=new InstantMessage(username,entry.getID(),message);
		instance.send(im, sendcallback);
	}
	
	/**
	 * deal the receiving messages
	 * @param messages
	 */
	public void dealMessages(ArrayList<InstantMessage>messages)
	{
		for(int i=0;i<messages.size();i++)
		{
			dealMessage(messages.get(i));
		}
	}
	
	/**
	 * remove the ChatWindow associating with the entry
	 * @param entry
	 */
	public void removeChatWindow(GroupEntry entry)
	{
		map.remove(entry);
	}
	
	/**
	 * deal the InstantMessage received,it chat window already existed,
	 * just append,else
	 * it will create a new chatwindow and append
	 * @param im
	 */
	public void dealMessage(InstantMessage im)
	{		
		String fromid=im.getFromID();
		GroupEntry entry=this.getEntry(fromid);
		ChatWindow cw=map.get(entry);//lookup the chat window in the HashMap
		if(cw==null)
		{
			cw=new ChatWindow(this,entry);
			cw.append(im);
			cw.setVisible(true);
			map.put(entry, cw);
		}
		else
		{
			cw.append(im);//just append a message
			cw.setVisible(true);
		}		
	}
	
	/**
	 * get the groupentry according to the 
	 * from id.
	 * if not found,return null;
	 * @param fromid
	 * @return
	 */
	private GroupEntry getEntry(String fromid)
	{
		for(int i=0;i<groups.size();i++)
		{
			Group group=groups.get(i);
			ArrayList<GroupEntry> entries=group.getGroupEntries();
			for(int j=0;j<entries.size();j++)
			{
				GroupEntry entry=entries.get(j);
				if(entry.getID().equals(fromid))
				{
					return entry;
				}
			}
		}
		return null;
	}
	
	/**
	 * return the id for short
	 * @param input
	 * @return
	 */
	private String getShortId(String input)
	{
		int index=input.indexOf("/");
		if(index<0)return input;
		else
		{
			return input.substring(0,index);
		}
	}	
	
	/**
	 * create a new chatwindow 
	 * @author wangkaidi
	 *
	 */
	private class MyTreeNodeListener extends TreeNodeListenerAdapter
	{
		public void onDblClick(Node node, EventObject e) 
		{
			MyTreeNode treenode=(MyTreeNode)node;
			//System.out.println("select "+treenode.getEntry().getAlias());			
			GroupEntry entry=treenode.getEntry();
			if(!map.containsKey(entry))
			{
				ChatWindow window=new ChatWindow(Client.this,treenode.getEntry());
				window.setVisible(true);
				map.put(entry, window);
			}
		}	
	}	
}
